/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.flexengine.logger;

import com.flexengine.time.TimeManager;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;

/**
 * @author Luann R. Athayde
 * @version 1.0
 * @since 1.0
 */
public class Logger {

    // -- Default constructor...
    private Logger() {
    }

    public static final int DEBUG_NONE = 0x00;
    public static final int DEBUG_INFO = 0xF0;
    public static final int DEBUG_WARNING = 0xF1;
    public static final int DEBUG_ERROR = 0xF2;
    public static final int DEBUG_ALL = 0xF3;

    private final static LinkedLogger log;
    private static int debugLevel;
    private static boolean autoClear;
    private final static ArrayList<PrintStream> streams;

    static {
        log = new LinkedLogger();
        debugLevel = DEBUG_NONE;
        autoClear = true;
        streams = new ArrayList<>();
    }

    //public static void show(LoggerType type, String msg)  {
    public static void show() {
        //System.out.println("Logger - show(): PrintStreams = "+streams);
        DataLogger dl = log.getLast();
        if (dl == null) {
            return;
        }
        switch (dl.getType()) {
            case ERRO:
                //streams.get(0).println("[ERROR] "+msg);
                System.err.println(dl);
                debugDataLogger(dl);
                break;
            case WARN:
                //streams.get(0).println("[WARNING] "+msg);
                System.err.println(dl);
                debugDataLogger(dl);
                break;
            case INFO:
                //streams.get(1).println("[MESSAGE] "+msg);
                System.out.println(dl);
                debugDataLogger(dl);
                break;
            case CORE:
                //streams.get(1).println("[CORE] "+msg);
                System.out.println(dl);
                debugDataLogger(dl);
                break;
        }
    }

    private static void debugDataLogger(DataLogger dl) {
        for (int i = 0; i < streams.size(); i++) {
            PrintStream ps = streams.get(i);
            //ps.println("["+type+"] "+msg);
            ps.println(dl);
        }
    }

    public static void log(LoggerType type, String msg) {
        try {
            log.add(new DataLogger(type, new StringBuffer(msg), TimeManager.getDate()));
            if (debugLevel == DEBUG_ALL) {
                show();
            } else if (debugLevel != DEBUG_NONE) {
                switch (log.getLast().getType()) {
                    case CORE:
                        show();
                        break;
                    case INFO:
                        if (debugLevel == DEBUG_INFO) {
                            show();
                        }
                        break;
                    case WARN:
                        if (debugLevel == DEBUG_WARNING) {
                            show();
                        }
                        break;
                    case ERRO:
                        if (debugLevel == DEBUG_ERROR) {
                            show();
                        }
                        break;
                }
            }
        } catch (FullLoggerException fle) {
            if (autoClear) {
                clear();
            }
        }
    }

    public static void logCore(String msg) {
        log(LoggerType.CORE, msg);
    }

    public static void logMessage(String msg) {
        log(LoggerType.INFO, msg);
    }

    public static void logWarning(String msg) {
        log(LoggerType.WARN, msg);
    }

    public static void logError(String msg) {
        log(LoggerType.ERRO, msg);
    }

    public static void logMessage(Class clazz, String method, String msg) {
        try {
            StringBuilder builder = new StringBuilder(clazz.getSimpleName());
            builder.append(" - ");
            builder.append(method);
            builder.append("(): ");
            builder.append(msg);
            Logger.logMessage(builder.toString());
        } catch (Exception e) {
        }
    }

    public static void clear() {
        log.clear();
        logMessage("Logger was cleared...");
        System.gc();
    }

    public static DataLogger getLastLog() {
        return log.getLast();
    }

    public static int getDebugLevel() {
        return debugLevel;
    }

    public static void setDebugLevel(int debugLevel) {
        Logger.debugLevel = debugLevel;
    }

    public static boolean setMaxSize(int max) {
        if (max > 0 && max <= 262144) {
            log.setMaxSize(max);
            logMessage("Logger size was changed to: " + max + ".");
            return true;
        } else {
            logWarning("The max size for the logger can't be more large then 262144 or minor that 1.");
        }
        return false;
    }

    public static int size() {
        return log.size();
    }

    public static LinkedLogger getLog() {
        return log;
    }

    public static boolean isAutoClear() {
        return autoClear;
    }

    public static void setAutoClear(boolean autoClear) {
        Logger.autoClear = autoClear;
    }

    public static void setStreams(ArrayList<PrintStream> streams) {
        Logger.streams.clear();
        Logger.streams.addAll(streams);
    }

    public static ArrayList<PrintStream> getStreams() {
        return streams;
    }

    public static boolean addPrintStream(PrintStream ps) {
        return streams.add(ps);
    }

    public static boolean addPrintStream(String file) {
        try {
            File logFile = new File("./log/" + file + ".log");
            logFile.delete();
            logFile.mkdirs();
            logFile.delete();
            logFile.createNewFile();
            Logger.addPrintStream(new PrintStream(logFile));
        } catch (IOException e) {
            Logger.logError("Logger - addPrintStream(): " + e);
            return false;
        }
        return true;
    }

    public static PrintStream removePrintStream(int index) {
        return streams.remove(index);
    }

    public static boolean removePrintStream(PrintStream ps) {
        return streams.remove(ps);
    }

    public static void clearStreams() {
        streams.clear();
    }
}
